/*
 * 创建日期 2011-3-3
 *
 * 成都天和软件公司
 * 电话：028-85425861 
 * 传真：028-85425861-8008 
 * 邮编：610041 
 * 地址：成都市武侯区航空路6号丰德万瑞中心B座1001 
 * 版权所有
 */
package  org.fantasy.common.db.pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 连接池管理
 * @author 王文成
 * @version 1.0
 * @since 2011-3-24
 */
public class ConnectionManager {

	private Log log = LogFactory.getLog(ConnectionManager.class);

	/**
	 * 当前使用的连接数
	 */
	private int checkout;

	/**
	 * 数据库配置
	 */
	private DBOptions options;

	/**
	 * 连接池
	 */
	private Vector<Connection> freeConnections = new Vector<Connection>();

	public ConnectionManager(DBOptions options) {
		this.options = options;
		this.init();
	}

	void init() {
		String driverClassName = options.getDriverClassName();
		try {
			Class.forName(driverClassName);
			//预先创建N个连接
			//for (int i = 0; i < options.getMinConnection(); i++) {
			//	freeConnections.add(getConnection());
			//}
		} catch (Exception e) {
			e.printStackTrace();
			log.fatal("ConnectionManager: Unable to load driver = " + driverClassName, e);
		}
	}

	/**
	 * 取得数据库连接
	 * 
	 * @return
	 * @throws Exception
	 */
	synchronized Connection getConnection() throws SQLException {
		int maxConnection = options.getMaxConnection();
		Connection conn = null;
		if (freeConnections.isEmpty() && checkout < maxConnection) {
			conn = newConnection();
			log.info("Create new connection from " + options + " ![" + checkout + "]");
		} else if( !freeConnections.isEmpty() ) {
			conn = freeConnections.remove(0);
			if (conn.isClosed()) {
				log.info("[" + checkout + "]Removed bad connection in ConnectionPool.");
				return null;
			}
			log.info("Get connection from pool " + options + "![" + checkout + "]");
		}
		
		if (conn != null) {
			checkout++;
		}
		return conn;
	}

	/**
	 * 取得数据库连接
	 * 
	 * @return
	 * @throws Exception
	 */
	Connection getConnection(int timeout) throws SQLException {
		Connection conn = null;
		long startTime = System.currentTimeMillis();
		while ((conn = getConnection()) == null) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			if (elapsedTime > timeout)
				break;
			try {
				Thread.sleep(timeout);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		return conn;
	}

	/**
	 * 创建数据库连接
	 * 
	 * @return
	 * @throws Exception
	 */
	synchronized Connection newConnection() throws SQLException {
		String url = options.getDatabaseURL();
		String user = options.getUser();
		String password = options.getPassword();
		if( user == null || password == null )
			return DriverManager.getConnection(url);
		else
			return DriverManager.getConnection(url, user, password);
	}

	/**
	 * 释放数据库连接
	 * 
	 * @param conn
	 * @throws Exception
	 */
	synchronized void freeConnection(Connection conn){
		if (conn != null) {
			if (checkout > 0)
				checkout--;
			freeConnections.add(conn);
			log.info("FreeConnection! [checkout=" + checkout + ";free=" + freeConnections.size() + "]");
		}else{
			log.info("Error connection! [" + conn + "]");
		}
	}

	/**
	 * 释放所有连接
	 * 
	 * @return
	 */
	synchronized void release() {
		for (Connection conn : freeConnections) {
			if (conn != null) {
				try {
					conn.close();
				} catch (SQLException e) {
					log.error("Can't close connection in ConnectionPool.");
				}
			}
		}
		checkout = 0;
	}
	
	DBOptions getOptions() {
		return options;
	}

	int getCheckout() {
		return checkout;
	}
}
